/*
    Seminar Computergrafik SS2012
    Praktikum
    Fachhochschule Münster
    Fachbereich Elektrotechnik und Informatik    
    
    Autoren: Alexander Kuhn & Mark Ruffer
*/
/* strict Modus nutzen */
"use strict";

/* WebGL Objekt */
var gl;

/* Das Canvas Zeichenfeld */
var canvas;

/* Texturen */
//var texture;
var textureDog;
var textureBody;
var textureHead;
var textureSky;
var textureGras;

var vertexTextureCoordBuffer;
var vertexTextureCoordBufferHead;
var vertexTextureCoordBufferBody;
var vertexTextureCoordBufferArmsLegs;
var vertexTextureCoordBufferSkyGras;

/* Speicher fuer Vertex Positionen */
var vBufferBody;
var vBufferLeftLeg;
var vBufferRightLeg;
var vBufferLeftArm;
var vBufferRightArm;
var vBufferHead;

var vBufferBodyDog;
var vBufferLeftLegDog;
var vBufferRightLegDog;
var vBufferLeftArmDog;
var vBufferRightArmDog;
var vBufferHeadDog;

var vLightSourceBuffer;

var vSkyBoxBuffer;
var vGrasBuffer;

/* Textur - Wiederholungsraten */
var textureRepeatGras = 5; 

/* Speicher fuer Farbinformationen */
// NOT IN USE

/* NOT IN USE
var cBufferStandardCube = [
    [0.5,   0.5,    0.5,    1.0],
    [0.5,   0.5,    0.5,    1.0],
    [0.5,   0.5,    0.5,    1.0],
    [0.5,   0.5,    0.5,    1.0],
    [0.5,   0.5,    0.5,    1.0],
    [0.5,   0.5,    0.5,    1.0]
];
*/

/* Licht */
var vertexNormalsBuffer;

/* Speicher fuer Indexinformationen */
var iBuffer;

/* Standardwerte fuer Wuerfelindizes */
var iBufferStandardCube = [
    0, 1, 2,      0, 2, 3,     /* front */ 
    4, 5, 6,      4, 6, 7,     /* hinten */
    8, 9, 10,     8, 10, 11,   /* oben */  
    12, 13, 14,   12, 14, 15,  /* unten */ 
    16, 17, 18,   16, 18, 19,  /* rechts */
    20, 21, 22,   20, 22, 23   /* links */ 
];

/* Buffer fuer das Koordinatensystem */
var vertexAxisXBuffer;
var vertexAxisYBuffer;
var vertexAxisZBuffer;

/* Matrizen */
var pMatrix = mat4.create();      /* Projektionsmatrix */
var mvMatrix = mat4.create();     /* Model-View-Matrix */

/* Stacks */
var mvMatrixStack = [];           /* Stack fuer die mvMatrix */

/* Shaderprogramme */
var shaderProgram;

/* Animationsvariablen */
var controlCheck = 1;
var reset = false;
var rRobotX = 0;                    
var rRobotY = 0;
var rLegs = 0;
var rArms = 0;
var rHead = 0;
var rTorso = 0;
var lastTime = 0;
var plusitLegs = true;
var plusitArms = true;
var plusitHead = true;
var plusitTorso = true;

var rotateRobotX = 0;
var rotateRobotY = 0;
var startzoom = -200;
var zoom = startzoom;

var rotateSceneY = 0;
var rotateSceneX = 0;
var rotateSceneZ = 0;

var keyPressed = [];

//Dog-Variablen
var xTrans = 0;
var yTrans = 0;
var rDog = 0;                    /* rotation des wuerfels */
var rLegsDog = 0;
var rArmsDog = 0;
var rHeadDog = 0;
var rTorsoDog = 0;
var plusitLegsDog = true;
var plusitArmsDog = true;
var plusitHeadDog = true;
var plusitTorsoDog = true;
var transXDog = -50.0;	// Verschiebung in der X-Achse
var transYDog = 0.0;	// Verschiebung in der Y-Achse (hoch und runter) wird vorerst nicht benötigt
var transZDog = 0.0;  // Verschiebung in der Z-Achse
var plusitMoveDog = false;


// Bezier Objekt
var bezier = new WebGLBezier();
var p1  = {};
var p2  = {};
var p3  = {};
var p4  = {};
var points;
var werte;
var textu;
var normals;
var dichte = 100;
var i = 0;
var curveCounter = 3;

/**
 * Wrapper zum Berechnen der Bezierkurve
 * @param arPointObjects Array mit den Punktobjektes für die Bezierkurve
 * @param dichte Anzahl Punkte, die auf der Kurve berechnet werden 
 * @return Array mit Kurvenpunkten
 */   
function calcBezierCurve(arPointObjects, dichte){
    points = arPointObjects;
    bezier.setPoints_as_Object(points);
    return bezier.getBezierKurve_as_Object(dichte);
}
// Info-Link: http://www.marcus-spengler.de/webgl/objecte/docs/symbols/WebGLBezier.html
// Beispiel-Code-Link: view-source:http://www.marcus-spengler.de/webgl/glsl/beispiele/bezier.php?back=seite-11.php


/**
 * Berechnet die verwendete Bezierkurve, anhand derer der Hund um den Roboter läuft.
 * Fuer die Kurvenerstellung kann test.html verwendet werden.
 */   
function setCurvePoints(){
    var valuesTmp; 
	
	// Festgelegte Koordinatenpunkte zur Berechnung der Bezier-Kurve
    p1.x = -50.0;
    p1.y =   0.0;
    p1.z =   0.0;

    p2.x = -100.0;
    p2.y =  0.0;
    p2.z = -50.0;

    p3.x =  10.0;
    p3.y =  0.0;
    p3.z = -50.0;

    p4.x =  50.0;
    p4.y =   0.0;
    p4.z =   0.0;
    
    werte = calcBezierCurve([p1, p2, p3, p4], dichte);
    
    p1.x =   0.0;
    p1.y =   0.0;
    p1.z =  75.0;

    p2.x = -60.0;
    p2.y =   0.0;
    p2.z =  70.0;

    p3.x = -20.0;
    p3.y =   0.0;
    p3.z =  50.0;

    p4.x = -50.0;
    p4.y =   0.0;
    p4.z =   0.0;
    
    valuesTmp = calcBezierCurve([p1, p2, p3, p4], dichte);
    for(i=0; i<dichte; i++){
        werte.push(valuesTmp[i]);
    }
    
    p1.x =  50.0;
    p1.y =   0.0;
    p1.z =   0.0;

    p2.x =  70.0;
    p2.y =   0.0;
    p2.z =  50.0;

    p3.x =  50.0;
    p3.y =   0.0;
    p3.z =  70.0;

    p4.x =   0.0;
    p4.y =   0.0;
    p4.z =  75.0; 

    
    valuesTmp = calcBezierCurve([p1, p2, p3, p4], dichte);
    for(i=0; i<dichte; i++){
        werte.push(valuesTmp[i]);
    }
}

/**
 * Berechnet die "Sichtrichtung" des Hundes zwischen zwei Punkten.
 * Entspricht dem Winkel zwischen zwei Punkten
 * 
 * @param p1 Startpunkt
 * @param p2 Zielpunkt
 * @return w Winkel in Grad
 */      
function viewingRotation(p1, p2){
    var dx, dy, dz, w;
    
    dx = p2.x - p1.x;
    dz = p2.z - p1.z;
    dy = Math.sqrt( dx*dx + dz*dz );
    w = radToDeg(Math.asin( dz/dy ));

    /* Korrektur im 4. Quadranten */
    if ( p2.x >= p1.x && p2.y <= p1.y ) {
        w = 180 - w;
    }
        
    return w;
}

/**
 * Setzt den Drehwinkel so, dass 90Â° bzw 45Â° pro Sekunde gedreht werden. Es wird
 * nicht in jedem Durchlauf ein fester Wert gedreht, sondern Abhaengig von der ver-
 * gangenen Zeit, sodass die Animation pro Zeit fest rotiert.
 * 
 * TODO: geht das effizienter ?    
 */ 
function animate(){
    var timeNow, elapsed, interm;
    timeNow = new Date().getTime(); // getTime(): Liefert die Anzahl Millisekunden als Zahl zurück, die seit dem 1. Januar 1970, 0:00:00 Uhr UTC, bis zu dem im Datumsobjekt gespeicherten Zeitpunkt vergangen sind.
    if(lastTime !== 0){
        elapsed = timeNow - lastTime;		// Zeitdifferenz bzw. vergange Zeit
        rRobotX += (rotateRobotX * elapsed)/1000.0;
        rRobotY += (rotateRobotY * elapsed)/1000.0;
        
        /* Beine bewegen */
        interm = (90 * elapsed)/1000.0;
        if(plusitLegs){
            rLegs += interm;              
        } else {
            rLegs -= interm;
        }
        if(rLegs >= 33.0) {plusitLegs = false;}
        else if (rLegs <= -33.0) {plusitLegs = true;}
        // Dog-Part
        if(plusitLegsDog){
            rLegsDog += interm;              
        } else {
            rLegsDog -= interm;
        }
        if(rLegsDog >= 30.0){
        	plusitLegsDog = false;
        } else if (rLegsDog <= -30.0){
        	plusitLegsDog = true;
        }
        
        /* Arme bewegen */
        interm = (60 * elapsed)/1000.0;
        if(plusitArms){
            rArms += interm;
        } else {
            rArms -= interm;
        }
        if(rArms >= 75.0){
            plusitArms = false;
        } else if(rArms <= -25.0){
            plusitArms = true;
        }
        // Dog-Part
        if(plusitArmsDog){
        	rArmsDog += interm;
        } else {
        	rArmsDog -= interm;
        }
        if(rArmsDog >= 30.0){
        	plusitArmsDog = false;
        } else if(rArmsDog <= -30.0) {
        	plusitArmsDog = true;
        }
        
        /* Kopf bewegen */
        interm = (45 * elapsed)/1000.0;
        if(plusitHead) {
            rHead += interm;
        } else {
            rHead -= interm;
        }
        if(rHead >= 45.0){
            plusitHead = false;            
        } else if(rHead <= -45.0) {
            plusitHead = true;
        }
        // Dog-Part
        if(plusitHeadDog){
        	rHeadDog += interm;
        } else {
        	rHeadDog -= interm;
        }
        if(rHeadDog >= 30.0){
        	plusitHeadDog = false;
        } else if(rHeadDog <= -20.0){
        	plusitHeadDog = true;
        }

        /* Torso (Kopf, Arme und Koerper) bewegen */        
        interm = (45 * elapsed)/1000.0;
        if(plusitTorso){
            rTorso += interm;
        } else {
            rTorso -= interm;
        }
        if(rTorso >= 0.0) {
            plusitTorso = false;
        } else if(rTorso <= -45.0) {
            plusitTorso = true;
        }
        //Dog-Part
        if(plusitTorsoDog){
            rTorsoDog += interm;
        } else {
            rTorsoDog -= interm;
        }
        if(rTorsoDog >= 0.0){
            plusitTorsoDog = false;
        } else if(rTorsoDog <= -45.0) {
            plusitTorsoDog = true;
        }

        // Ausgabe des Elapsed-Wertes im Browser
        document.getElementById("elapsed").value = elapsed;
        
        
        /* Bewegung des gesamten Hundes ahand von Bezierkurven-Verlaeufe*/
        transXDog = werte[i].x;
        transYDog = werte[i].y;
        transZDog = werte[i].z;
        if(i+1 < curveCounter*dichte-1) {
            rDog = viewingRotation(werte[i], werte[i+1]);
        } else {
            rDog = viewingRotation(werte[i], werte[0]);
        }
        i = (i + 1) % (curveCounter*dichte - 1);
        document.getElementById("__rdog__").value = Math.round(rDog);
        
    }
    lastTime = timeNow;
}


/**
 * Initialisiert die Shader
 */ 
function initShaders(){
    var fragmentShader, vertexShader;
    
    fragmentShader = getShader(gl, gl.FRAGMENT_SHADER, shaderprogram_fragmentshader);
    vertexShader = getShader(gl, gl.VERTEX_SHADER, shaderprogram_vertexshader);

    /* das shaderProgram kann je einen fragment und vertex shader beherbergen */
    shaderProgram = gl.createProgram();
    gl.attachShader(shaderProgram, vertexShader);
    gl.attachShader(shaderProgram, fragmentShader);
    gl.linkProgram(shaderProgram);

    if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
      window.alert("Could not initialise shaders");
    }

    gl.useProgram(shaderProgram);

    /* 
        die position eines vertex wird als attribut an den shader geliefert.
        dazu wird die speicheradresse dieser shader variablen als zusÃ¤tzliche
        eigenschaft an das shaderprogram angehangen.
    */   
    shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
    gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
    
    /* adresse fÃ¼r attribut aVertexColor speichern */
    /* KEINE FARBEN MEHR -> TEXTUREN
    shaderProgram.vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor");
    gl.enableVertexAttribArray(shaderProgram.vertexColorAttribute);
    */
    
    /* adresse fÃ¼r attribut aTextureCoord speichern */
    shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
    gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute);
    
    shaderProgram.vertexNormalAttribute = gl.getAttribLocation(shaderProgram, "aVertexNormal");
    gl.enableVertexAttribArray(shaderProgram.vertexNormalAttribute);

    /* adressen der Uniforme speichern */    
    shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
    shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
    shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler");
    shaderProgram.nMatrixUniform = gl.getUniformLocation(shaderProgram, "uNMatrix");
    shaderProgram.ambientColorUniform = gl.getUniformLocation(shaderProgram, "uAmbientColor");
    shaderProgram.pointingLightPositionUniform = gl.getUniformLocation(shaderProgram, "uPointingLightPosition");
    shaderProgram.pointingLightColorUniform = gl.getUniformLocation(shaderProgram, "uPointingLightColor");
    shaderProgram.useTextureUniform = gl.getUniformLocation(shaderProgram, "uUseTexture");
    shaderProgram.useLightUniform = gl.getUniformLocation(shaderProgram, "uUseLight");
    shaderProgram.vertexColorUniform = gl.getUniformLocation(shaderProgram, "uVertexColor");
}

/**
 * Initialisiert die SpeicherblÃ¶cke
 */ 
function initBuffers(){
    var vertices;
    var axisVertices;
    
    /* X-Achse mit Pfeilspitze*/
    axisVertices = [
        -30.0,   0.0,    0.0,
        30.0,    0.0,    0.0,
        29.0,    1.0,    0.0,
        29.0,    -1.0,   0.0,
        30.0,    0.0,    0.0
    ];
    vertexAxisXBuffer = initBuffer(gl, gl.ARRAY_BUFFER, axisVertices, gl.STATIC_DRAW, 5, 3, 0);
    
    /* y-Achse mit Rechteckspitze*/
    axisVertices = [
        0.0,    -30.0,  0.0,
        0.0,    30.0,   0.0,
        -1.0,   30.0,   0.0,
        -1.0,   29.0,   0.0,
        1.0,    29.0,   0.0,
        1.0,    30.0,   0.0,
        0.0,    30.0,   0.0
    ];
    vertexAxisYBuffer = initBuffer(gl, gl.ARRAY_BUFFER, axisVertices, gl.STATIC_DRAW, 7, 3, 0);
    
    /* Z-Achse mit Strichspitze */
    axisVertices = [
        0.0,    0.0,    -30.0,
        0.0,    0.0,    30.0,
        0.0,    1.0,    30.0,
        0.0,    -1.0,   30.0
    ];
    vertexAxisZBuffer = initBuffer(gl, gl.ARRAY_BUFFER, axisVertices, gl.STATIC_DRAW, 4, 3, 0);

    var textureCoords = [
      // Front face
      0.0, 0.5,
      0.5, 0.5,
      0.5, 1.0,
      0.0, 1.0,

      // Back face
      0.0, 0.0,
      0.5, 0.0,
      0.5, 0.5,
      0.0, 0.5,

      // Top face
      0.0, 0.0,
      0.5, 0.0,
      0.5, 0.5,
      0.0, 0.5,

      // Bottom face
      0.0, 0.0,
      0.5, 0.0,
      0.5, 0.5,
      0.0, 0.5,

      // Right face
      0.0, 0.0,
      0.5, 0.0,
      0.5, 0.5,
      0.0, 0.5,

      // Left face
      0.0, 0.0,
      0.5, 0.0,
      0.5, 0.5,
      0.0, 0.5
    ];
    
    vertexTextureCoordBufferHead = initBuffer(gl, gl.ARRAY_BUFFER, textureCoords, gl.STATIC_DRAW, 24, 2, 0);
    
    textureCoords = [
      // Front face
      0.0, 0.0,
      0.5, 0.0,
      0.5, 0.5,
      0.0, 0.5,

      // Back face
      0.5, 0.0,
      1.0, 0.0,
      1.0, 0.5,
      0.5, 0.5,

      // Top face
      0.5, 0.0,
      1.0, 0.0,
      1.0, 0.5,
      0.5, 0.5,

      // Bottom face
      0.5, 0.0,
      1.0, 0.0,
      1.0, 0.5,
      0.5, 0.5,

      // Right face
      0.0, 0.5,
      0.0625, 0.5,
      0.0625, 1.0,
      0.0, 1.0,

      // Left face
      0.0, 0.5,
      0.0625, 0.5,
      0.0625, 1.0,
      0.0, 1.0
    ];
    vertexTextureCoordBufferBody = initBuffer(gl, gl.ARRAY_BUFFER, textureCoords, gl.STATIC_DRAW, 24, 2, 0);
    
    textureCoords = [
      // Front face
      0.0, 0.5,
      0.0625, 0.5,
      0.0625, 1.0,
      0.0, 1.0,

      // Back face
      0.0, 0.5,
      0.0625, 0.5,
      0.0625, 1.0,
      0.0, 1.0,

      // Top face
      0.5, 0.0,
      1.0, 0.0,
      1.0, 0.5,
      0.5, 0.5,

      // Bottom face
      0.5, 0.0,
      1.0, 0.0,
      1.0, 0.5,
      0.5, 0.5,

      // Right face
      0.0, 0.5,
      0.0625, 0.5,
      0.0625, 1.0,
      0.0, 1.0,

      // Left face
      0.0, 0.5,
      0.0625, 0.5,
      0.0625, 1.0,
      0.0, 1.0
    ];
    vertexTextureCoordBufferArmsLegs = initBuffer(gl, gl.ARRAY_BUFFER, textureCoords, gl.STATIC_DRAW, 24, 2, 0);
    
    //Dog-Part
    textureCoords = [
	     // Front face
	     0.0, 0.0,
	     1.0, 0.0,
	     1.0, 1.0,
	     0.0, 1.0,
	
	     // Back face
	     1.0, 0.0,
	     1.0, 1.0,
	     0.0, 1.0,
	     0.0, 0.0,
	
	     // Top face
	     0.0, 1.0,
	     0.0, 0.0,
	     1.0, 0.0,
	     1.0, 1.0,
	
	     // Bottom face
	     1.0, 1.0,
	     0.0, 1.0,
	     0.0, 0.0,
	     1.0, 0.0,
	
	     // Right face
	     1.0, 0.0,
	     1.0, 1.0,
	     0.0, 1.0,
	     0.0, 0.0,
	
	     // Left face
	     0.0, 0.0,
	     1.0, 0.0,
	     1.0, 1.0,
	     0.0, 1.0
	   ];
    
    vertexTextureCoordBuffer = initBuffer(gl, gl.ARRAY_BUFFER, textureCoords, gl.STATIC_DRAW, 24, 2, 0);

    /* Texturkoordinaten für Skybox und Boden */
    textureCoords = [
	     // Front face
	     0.0, 0.0,
	     textureRepeatGras, 0.0,
	     textureRepeatGras, textureRepeatGras,
	     0.0, textureRepeatGras,
	
	     // Back face
	     textureRepeatGras, 0.0,
	     textureRepeatGras, textureRepeatGras,
	     0.0, textureRepeatGras,
	     0.0, 0.0,
	
	     // Top face
	     0.0, textureRepeatGras,
	     0.0, 0.0,
	     textureRepeatGras, 0.0,
	     textureRepeatGras, textureRepeatGras,
	
	     // Bottom face
	     textureRepeatGras, textureRepeatGras,
	     0.0, textureRepeatGras,
	     0.0, 0.0,
	     textureRepeatGras, 0.0,
	
	     // Right face
	     textureRepeatGras, 0.0,
	     textureRepeatGras, textureRepeatGras,
	     0.0, textureRepeatGras,
	     0.0, 0.0,
	
	     // Left face
	     0.0, 0.0,
	     textureRepeatGras, 0.0,
	     textureRepeatGras, textureRepeatGras,
	     0.0, textureRepeatGras
	   ];
       
       vertexTextureCoordBufferSkyGras = initBuffer(gl, gl.ARRAY_BUFFER, textureCoords, gl.STATIC_DRAW, 24, 2, 0);    
    
    /* Licht */
    /* Normalen fÃ¼r alle Vertizes festlegen */
    var vertexNormals = [
    // Front face
       0.0,  0.0,  1.0,
       0.0,  0.0,  1.0,
       0.0,  0.0,  1.0,
       0.0,  0.0,  1.0,

      // Back face
       0.0,  0.0, -1.0,
       0.0,  0.0, -1.0,
       0.0,  0.0, -1.0,
       0.0,  0.0, -1.0,

      // Top face
       0.0,  1.0,  0.0,
       0.0,  1.0,  0.0,
       0.0,  1.0,  0.0,
       0.0,  1.0,  0.0,

      // Bottom face
       0.0, -1.0,  0.0,
       0.0, -1.0,  0.0,
       0.0, -1.0,  0.0,
       0.0, -1.0,  0.0,

      // Right face
       1.0,  0.0,  0.0,
       1.0,  0.0,  0.0,
       1.0,  0.0,  0.0,
       1.0,  0.0,  0.0,

      // Left face
      -1.0,  0.0,  0.0,
      -1.0,  0.0,  0.0,
      -1.0,  0.0,  0.0,
      -1.0,  0.0,  0.0
    ];
    vertexNormalsBuffer = initBuffer(gl, gl.ARRAY_BUFFER, vertexNormals, gl.STATIC_DRAW, 24, 3, 0);
    
    /* ***** Standard Index Buffer ***** */
    iBuffer = initBuffer(gl, gl.ELEMENT_ARRAY_BUFFER, iBufferStandardCube, gl.STATIC_DRAW, 36, 1, 1);
    
    /* ***** BODY ***** */
    vertices = cubeArray(-10.0, -10.0, 2.5, 20.0, 20.0, 5.0);

    vBufferBody = initBuffer(gl, gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW, 24, 3, 0);
    
    /* ***** LEFT LEG ***** */
    vertices = cubeArray(-10.0, -35.0, 2.5, 5.0, 20.0, 5.0);

    vBufferLeftLeg = initBuffer(gl, gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW, 24, 3, 0);
    
    /* ***** RIGHT LEG ***** */
    vertices = cubeArray(5.0, -35.0, 2.5, 5.0, 20.0, 5.0);
    
    vBufferRightLeg = initBuffer(gl, gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW, 24, 3, 0);
    
    /* ***** LEFT ARM ***** */
    vertices = cubeArray(-15.0, -8.0, 0.5, 2.0, 16.0, 2.0);
    
    vBufferLeftArm = initBuffer(gl, gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW, 24, 3, 0);
    
    /* ***** RIGHT ARM ***** */
    vertices = cubeArray(13.0, -8.0, 2.0, 2.0, 16.0, 2.0);
    
    vBufferRightArm = initBuffer(gl, gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW, 24, 3, 0);
    
    /* ***** HEAD ***** */
    vertices = cubeArray(-5.0, 15.0, 2.5, 10.0, 10.0, 5.0);
    
    vBufferHead = initBuffer(gl, gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW, 24, 3, 0);
    
    //======Dog-Part=======
    
    /* ***** Dog: BODY ***** */
	//cubeArray(x, y, z, width, height, depth)
	vertices = cubeArray(-10.0, -10.0, 0.0, 30.0, 10.0, 6.0);
	
	vBufferBodyDog = initBuffer(gl, gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW, 24, 3, 0);
	//cBufferBodyDog = initBuffer(gl, gl.ARRAY_BUFFER, unpackColors(cBufferStandardCube), gl.STATIC_DRAW, 24, 4, 0);
	
	/* ***** Dog: LEFT LEG ***** */
	vertices = cubeArray(15.0, -20.0, 4.0, 2.0, 16.0, 2.0);
	
	vBufferLeftLegDog = initBuffer(gl, gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW, 24, 3, 0);
	//cBufferLeftLegDog = initBuffer(gl, gl.ARRAY_BUFFER, unpackColors(cBufferStandardCube), gl.STATIC_DRAW, 24, 4, 0);
	
	/* ***** Dog: RIGHT LEG ***** */
	vertices = cubeArray(15.0, -20.0, -8.0, 2.0, 16.0, 2.0);
	
	vBufferRightLegDog = initBuffer(gl, gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW, 24, 3, 0);
	//cBufferRightLegDog = initBuffer(gl, gl.ARRAY_BUFFER, unpackColors(cBufferStandardCube), gl.STATIC_DRAW, 24, 4, 0);
	
	/* ***** Dog: LEFT ARM ***** */
	vertices = cubeArray(-5.0, -20.0, 4.0, 2.0, 16.0, 2.0);
	
	vBufferLeftArmDog = initBuffer(gl, gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW, 24, 3, 0);
	//cBufferLeftArmDog = initBuffer(gl, gl.ARRAY_BUFFER, unpackColors(cBufferStandardCube), gl.STATIC_DRAW, 24, 4, 0);
	
	/* ***** Dog: RIGHT ARM ***** */
	vertices = cubeArray(-5.0, -20.0, -8.0, 2.0, 16.0, 2.0);
	
	vBufferRightArmDog = initBuffer(gl, gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW, 24, 3, 0);
	//cBufferRightArmDog = initBuffer(gl, gl.ARRAY_BUFFER, unpackColors(cBufferStandardCube), gl.STATIC_DRAW, 24, 4, 0);
	
	/* ***** Dog: HEAD ***** */
	vertices = cubeArray(-20.0, 5.0, 0.0, 10.0, 10.0, 6.0);
	
	vBufferHeadDog = initBuffer(gl, gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW, 24, 3, 0);
	//cBufferHeadDog = initBuffer(gl, gl.ARRAY_BUFFER, unpackColors(cBufferStandardCube), gl.STATIC_DRAW, 24, 4, 0);
	
	/* *** SKYBOX *** */
	vertices = cubeArray(-1000.0, -1000.0, 1000.0, 2000.0, 2000.0, 2000.0);
	vSkyBoxBuffer = initBuffer(gl, gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW, 24, 3, 0);
	
	/* *** Gras *** */
	vertices = cubeArray(-1000.0, -38.0, 1000.0, 2000.0, 5.0, 2000.0);
	vGrasBuffer = initBuffer(gl, gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW, 24, 3, 0);
    
}

/**
 * FÃ¼hrt die Berechnungen auf der Grafikkarte durch und bringt die erzeugte Grafik auf
 * die ZeichenflÃ¤che
 */  
function drawScene(){
    /* Viewport definieren ueber der Groesse des Canvas */
    gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
    /* Zeichenflaeche leeren */
    gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);
    
    /*
        perspektive festlegen:
            45Â° blickwinkel
            seitenverhaeltnis des canvas
            nur elemente, die weiter weg sind als 0.1 einheiten
            nur elemente, die nÃ¤her sind als 100 einheiten
            
    */
    mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 5000.0, pMatrix);
    
    /* Einheitsmatrix erzeugen */    
    mat4.identity(mvMatrix);
    
    /* Texturen vorladen */
    bindTextures([gl.TEXTURE0, gl.TEXTURE1, gl.TEXTURE2, gl.TEXTURE3, gl.TEXTURE4], [gl.TEXTURE_2D, gl.TEXTURE_2D, gl.TEXTURE_2D, gl.TEXTURE_2D, gl.TEXTURE_2D], [textureHead, textureBody, textureDog, textureSky, textureGras]);
    
    /* Licht einschalten */
    gl.uniform1i(shaderProgram.useLightUniform, true);
    
    /* gesamtes Bild verschieben */
    if(reset === true){
        mat4.translate(mvMatrix, [xTrans, yTrans, zoom]);
        reset = false;
    } else {
        mat4.translate(mvMatrix, [xTrans, yTrans, zoom]);
    }
    
    /* ***** Kameradrehung ***** */
	mat4.rotate(mvMatrix, degToRad(rotateSceneY), [0, 1, 0]);
    mat4.rotate(mvMatrix, degToRad(rotateSceneX), [1, 0, 0]);
    mat4.rotate(mvMatrix, degToRad(rotateSceneZ), [0, 0, 1]);

    
    
    /* ***** Licht ***** */
    /* Umgebungslichtfarbe auslesen und an Shader uebergeben */
    gl.uniform3f(shaderProgram.ambientColorUniform, 
                 parseFloat(document.getElementById("LIGHT_ambient_r").value), 
                 parseFloat(document.getElementById("LIGHT_ambient_g").value), 
                 parseFloat(document.getElementById("LIGHT_ambient_b").value)
    );
    /* Lichtposition auslesen */
    var pointingX, pointingY, pointingZ;
    pointingX = parseFloat(document.getElementById("LIGHT_directional_x").value);
    pointingY = parseFloat(document.getElementById("LIGHT_directional_y").value);
    pointingZ = parseFloat(document.getElementById("LIGHT_directional_z").value);
    var adjustedLD = vec3.create([pointingX, pointingY, pointingZ]);
    
    /* Lichtpositionsvektor mit aktueller Drehung multiplizieren */
    mat4.multiplyVec3(mvMatrix, adjustedLD);
    
    /* Pointing Light Position und Farbe an Shader */
    var pointingR, pointingG, pointingB;
    pointingR = parseFloat(document.getElementById("LIGHT_directional_r").value);
    pointingG = parseFloat(document.getElementById("LIGHT_directional_g").value);
    pointingB = parseFloat(document.getElementById("LIGHT_directional_b").value);
    gl.uniform3fv(shaderProgram.pointingLightPositionUniform, adjustedLD);
    gl.uniform3f(shaderProgram.pointingLightColorUniform, pointingR, pointingG, pointingB);        
    
    /***** Achsen zeichnen *****/
    /* Texturen abschalten fuer Achsen und Farbe einstellen */
    gl.uniform1i(shaderProgram.useTextureUniform, false);
    gl.uniform4f(shaderProgram.vertexColorUniform, 1.0, 1.0, 1.0, 1.0);
    
    /* ***** Lichtquelle zeichnen ***** */
    /* LightSource Buffer */
    // TODO: initBuffer in drawScene eigentlich unerwÃ¼nscht ... (bufferData() ist langsam)
    var vertices = cubeArray(pointingX, pointingY, pointingZ, 2.0, 2.0, 2.0);
    vLightSourceBuffer = initBuffer(gl, gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW, 24, 3, 0);
    gl.uniform4f(shaderProgram.vertexColorUniform, pointingR, pointingG, pointingB, 1.0);    
    bindAndDraw(gl, shaderProgram, gl.TRIANGLES, vLightSourceBuffer, gl.ARRAY_BUFFER, gl.FLOAT, iBuffer, gl.ELEMENT_ARRAY_BUFFER, gl.UNSIGNED_SHORT, vertexTextureCoordBufferBody, gl.ARRAY_BUFFER, gl.FLOAT, vertexNormalsBuffer, gl.ARRAY_BUFFER, gl.FLOAT, 1);
    
    /* Texturen wieder einschalten */
    gl.uniform1i(shaderProgram.useTextureUniform, true);

    /* *** SKYBOX *** */
    /* Licht ausschalten */
    gl.uniform1i(shaderProgram.useLightUniform, false);
    gl.uniform4f(shaderProgram.vertexColorUniform, 0.5, 0.5, 0.5, 1.0);
    bindAndDraw(gl, shaderProgram, gl.TRIANGLES, vSkyBoxBuffer, gl.ARRAY_BUFFER, gl.FLOAT, iBuffer, gl.ELEMENT_ARRAY_BUFFER, gl.UNSIGNED_SHORT, vertexTextureCoordBuffer, gl.ARRAY_BUFFER, gl.FLOAT, vertexNormalsBuffer, gl.ARRAY_BUFFER, gl.FLOAT, 3);
    /* Licht einschalten */
    gl.uniform1i(shaderProgram.useLightUniform, true);
    
    /* Grasboden */
    bindAndDraw(gl, shaderProgram, gl.TRIANGLES, vGrasBuffer, gl.ARRAY_BUFFER, gl.FLOAT, iBuffer, gl.ELEMENT_ARRAY_BUFFER, gl.UNSIGNED_SHORT, vertexTextureCoordBufferSkyGras, gl.ARRAY_BUFFER, gl.FLOAT, vertexNormalsBuffer, gl.ARRAY_BUFFER, gl.FLOAT, 4);    

    /* Rotation des Roboters und Hundes */
    mat4.rotate(mvMatrix, degToRad(rRobotX), [1, 0, 0]);
    mat4.rotate(mvMatrix, degToRad(rRobotY), [0, 1, 0]);
    

    /* Laden und Zeichnen der Objekte */
    
    /* ***** BODY ***** */
    mvPushMatrix();    
	    mat4.translate(mvMatrix, [0.0, -10.0, 0.0]);
	    mat4.rotate(mvMatrix, degToRad(-rTorso), [1, 0, 0]);
	    mat4.translate(mvMatrix, [0.0, 10.0, 0.0]);
	    
	    bindAndDraw(gl, shaderProgram, gl.TRIANGLES, vBufferBody, gl.ARRAY_BUFFER, gl.FLOAT, iBuffer, gl.ELEMENT_ARRAY_BUFFER, gl.UNSIGNED_SHORT, vertexTextureCoordBufferBody, gl.ARRAY_BUFFER, gl.FLOAT, vertexNormalsBuffer, gl.ARRAY_BUFFER, gl.FLOAT, 1);
	    
	    /* ***** ARMs ***** */
	    mvPushMatrix();    
		    mat4.translate(mvMatrix, [0.0, 6.0, 0.0]);
		    mat4.rotate(mvMatrix, degToRad(-rArms), [1, 0, 0]);
		    mat4.translate(mvMatrix, [0.0, -6.0, 0.0]);
		    bindAndDraw(gl, shaderProgram, gl.TRIANGLES, vBufferLeftArm, gl.ARRAY_BUFFER, gl.FLOAT, iBuffer, gl.ELEMENT_ARRAY_BUFFER, gl.UNSIGNED_SHORT, vertexTextureCoordBufferArmsLegs, gl.ARRAY_BUFFER, gl.FLOAT, vertexNormalsBuffer, gl.ARRAY_BUFFER, gl.FLOAT, 1);
		    bindAndDraw(gl, shaderProgram, gl.TRIANGLES, vBufferRightArm, gl.ARRAY_BUFFER, gl.FLOAT, iBuffer, gl.ELEMENT_ARRAY_BUFFER, gl.UNSIGNED_SHORT, vertexTextureCoordBufferArmsLegs, gl.ARRAY_BUFFER, gl.FLOAT, vertexNormalsBuffer, gl.ARRAY_BUFFER, gl.FLOAT, 1);
	    mvPopMatrix();
	    /* ***** HEAD ***** */
	    mvPushMatrix();
		    mat4.rotate(mvMatrix, degToRad(rHead), [0, 1, 0]);
		    bindAndDraw(gl, shaderProgram, gl.TRIANGLES, vBufferHead, gl.ARRAY_BUFFER, gl.FLOAT, iBuffer, gl.ELEMENT_ARRAY_BUFFER, gl.UNSIGNED_SHORT, vertexTextureCoordBufferHead, gl.ARRAY_BUFFER, gl.FLOAT, vertexNormalsBuffer, gl.ARRAY_BUFFER, gl.FLOAT, 0);
	    mvPopMatrix();
	        
    mvPopMatrix();
    /* ***** LEGs ***** */
	mvPushMatrix();
	    mat4.translate(mvMatrix, [0.0, -18.0, 0.0]);
	    mat4.rotate(mvMatrix, degToRad(rLegs), [1, 0, 0]);
	    mat4.translate(mvMatrix, [0.0, 18.0, 0.0]);    
	    bindAndDraw(gl, shaderProgram, gl.TRIANGLES, vBufferLeftLeg, gl.ARRAY_BUFFER, gl.FLOAT, iBuffer, gl.ELEMENT_ARRAY_BUFFER, gl.UNSIGNED_SHORT, vertexTextureCoordBufferArmsLegs, gl.ARRAY_BUFFER, gl.FLOAT, vertexNormalsBuffer, gl.ARRAY_BUFFER, gl.FLOAT, 1);
    mvPopMatrix();
    mvPushMatrix();
	    mat4.translate(mvMatrix, [0.0, -18.0, 0.0]);
	    mat4.rotate(mvMatrix, degToRad(-rLegs), [1, 0, 0]);
	    mat4.translate(mvMatrix, [0.0, 18.0, 0.0]);
	    bindAndDraw(gl, shaderProgram, gl.TRIANGLES, vBufferRightLeg, gl.ARRAY_BUFFER, gl.FLOAT, iBuffer, gl.ELEMENT_ARRAY_BUFFER, gl.UNSIGNED_SHORT, vertexTextureCoordBufferArmsLegs, gl.ARRAY_BUFFER, gl.FLOAT, vertexNormalsBuffer, gl.ARRAY_BUFFER, gl.FLOAT, 1);
    mvPopMatrix();
    
    /* ***** Dog: BODY ***** */
    mvPushMatrix();
    	
    	/* Hund tiefer gesetzt - etwa auf Höhe der Beine des Roboters */
        mat4.translate(mvMatrix, [0, -15, 0]);
        
        /* Translation anhand der Bezierkurvenkoordinaten */
        mat4.translate(mvMatrix, [transXDog, transYDog, transZDog]);
        /* Drehung in Sichtrichtung */
    	mat4.rotate(mvMatrix, degToRad(rDog), [0, 1, 0]);
    	bindAndDraw(gl, shaderProgram, gl.TRIANGLES, vBufferBodyDog, gl.ARRAY_BUFFER, gl.FLOAT, iBuffer, gl.ELEMENT_ARRAY_BUFFER, gl.UNSIGNED_SHORT, vertexTextureCoordBuffer, gl.ARRAY_BUFFER, gl.FLOAT, vertexNormalsBuffer, gl.ARRAY_BUFFER, gl.FLOAT, 2);
    	
    	/* ***** ARMs ***** */
	    mvPushMatrix();    
	    mat4.translate(mvMatrix, [-3.0, -5.0, -4.0]);
	    mat4.rotate(mvMatrix, degToRad(rArmsDog), [0, 0, 1]);
	    //mat4.rotate(mvMatrix, degToRad(0), [0, 0, 1]);
	    mat4.translate(mvMatrix, [3.0, 5.0, 4.0]);
	    
	    bindAndDraw(gl, shaderProgram, gl.TRIANGLES, vBufferLeftArmDog, gl.ARRAY_BUFFER, gl.FLOAT, iBuffer, gl.ELEMENT_ARRAY_BUFFER, gl.UNSIGNED_SHORT, vertexTextureCoordBuffer, gl.ARRAY_BUFFER, gl.FLOAT, vertexNormalsBuffer, gl.ARRAY_BUFFER, gl.FLOAT, 2);
	    bindAndDraw(gl, shaderProgram, gl.TRIANGLES, vBufferRightArmDog, gl.ARRAY_BUFFER, gl.FLOAT, iBuffer, gl.ELEMENT_ARRAY_BUFFER, gl.UNSIGNED_SHORT, vertexTextureCoordBuffer, gl.ARRAY_BUFFER, gl.FLOAT, vertexNormalsBuffer, gl.ARRAY_BUFFER, gl.FLOAT, 2);
	    mvPopMatrix();
	    
	    /* ***** HEAD ***** */
	    mvPushMatrix();
	    mat4.rotate(mvMatrix, degToRad(rHeadDog), [0, 0, 1]);
	    bindAndDraw(gl, shaderProgram, gl.TRIANGLES, vBufferHeadDog, gl.ARRAY_BUFFER, gl.FLOAT, iBuffer, gl.ELEMENT_ARRAY_BUFFER, gl.UNSIGNED_SHORT, vertexTextureCoordBuffer, gl.ARRAY_BUFFER, gl.FLOAT, vertexNormalsBuffer, gl.ARRAY_BUFFER, gl.FLOAT, 2);
	    mvPopMatrix();
    
    /* ***** LEGs ***** */
	    mvPushMatrix();
	    mat4.translate(mvMatrix, [15.0, -5.0, 0.0]);
	    mat4.rotate(mvMatrix, degToRad(rLegsDog), [0, 0, 1]);
	    mat4.translate(mvMatrix, [-15.0, 5.0, 0.0]);
	    bindAndDraw(gl, shaderProgram, gl.TRIANGLES, vBufferLeftLegDog, gl.ARRAY_BUFFER, gl.FLOAT, iBuffer, gl.ELEMENT_ARRAY_BUFFER, gl.UNSIGNED_SHORT, vertexTextureCoordBuffer, gl.ARRAY_BUFFER, gl.FLOAT, vertexNormalsBuffer, gl.ARRAY_BUFFER, gl.FLOAT, 2);
	    mvPopMatrix();
	    mvPushMatrix();
	    mat4.translate(mvMatrix, [15.0, -5.0, 0.0]);
	    mat4.rotate(mvMatrix, degToRad(rLegsDog), [0, 0, 1]);
	    mat4.translate(mvMatrix, [-15.0, 5.0, 0.0]);
	    bindAndDraw(gl, shaderProgram, gl.TRIANGLES, vBufferRightLegDog, gl.ARRAY_BUFFER, gl.FLOAT, iBuffer, gl.ELEMENT_ARRAY_BUFFER, gl.UNSIGNED_SHORT, vertexTextureCoordBuffer, gl.ARRAY_BUFFER, gl.FLOAT, vertexNormalsBuffer, gl.ARRAY_BUFFER, gl.FLOAT, 2);
	    mvPopMatrix();
    mvPopMatrix();
}

/* QUICK AND DIRTY FPS MEASUREMENT */
var fps_lasttime = 0;
var fps_median = [];
var fps_counter = 0;
function measureFPS(){
    var now, val, sum, i;
    
    now = new Date().getTime();
    if(fps_lasttime !== 0){
        val = 1000/(now - fps_lasttime);
        fps_median[fps_counter] = val;
        fps_counter = (fps_counter+1) % 100;
        sum = 0;
        for(i=0; i<100; i++) {
            sum += fps_median[i];
        }
        if(!isNaN(sum/100)) {document.getElementById("FPS").value = Math.round(sum/100);}
        else {document.getElementById("FPS").value = "wait...";}
        
    }
    fps_lasttime = now;    
}
/* QUICK AND DIRTY FPS MEASUREMENT */

var mcheck=false;
function tick(){
    /* QUICK AND DIRTY FPS MEASUREMENT */
    if( document.getElementById("FPS_CHECK").checked === true ){
        measureFPS();
        mcheck=true;
    }
    else if(mcheck===true){
        mcheck=false;
        document.getElementById("FPS_CHECK").checked = false;
        document.getElementById("FPS").value = "";
    }
    /* QUICK AND DIRTY FPS MEASUREMENT */
    requestAnimFrame(tick);
    handleKeys();
    drawScene();
    animate();
}

/**
 * Erzeugt ein neues Texturobjekt, erzeugt ein Image Objekt und lÃ¤dt die
 * angegebene Bilddatei.
 */  
function initTextures(){
    textureBody = gl.createTexture();
    textureBody.image = new Image();
    textureBody.image.onload = function(){
        handleLoadedTexture(textureBody, gl.LINEAR, gl.LINEAR_MIPMAP_NEAREST, false);
    };
    textureBody.image.src = "./pictures/body.gif";
    
    textureHead = gl.createTexture();
    textureHead.image = new Image();
    textureHead.image.onload = function(){
        handleLoadedTexture(textureHead, gl.LINEAR, gl.LINEAR_MIPMAP_NEAREST, false);
    };
    textureHead.image.src = "./pictures/head.gif";
    
    textureDog = gl.createTexture();
    textureDog.image = new Image();
    textureDog.image.onload = function(){
        handleLoadedTexture(textureDog, gl.LINEAR, gl.LINEAR_MIPMAP_NEAREST, false);
    };
    textureDog.image.src = "./pictures/fell.gif";
    
    textureSky = gl.createTexture();
    textureSky.image = new Image();
    textureSky.image.onload = function(){
        handleLoadedTexture(textureSky, gl.LINEAR, gl.LINEAR_MIPMAP_NEAREST, false);
    };
    textureSky.image.src = "./pictures/sky.gif";
    
    textureGras = gl.createTexture();
    textureGras.image = new Image();
    textureGras.image.onload = function(){
        handleLoadedTexture(textureGras, gl.LINEAR, gl.LINEAR_MIPMAP_NEAREST, true);
    };
    textureGras.image.src = "./pictures/gras.gif";    
}

/**
 * Druecken einer Taste eintragen
 * @param event Javascript Event
 */  
function handlekeydown(event){
    keyPressed[event.keyCode] = true;
}

/**
 * Loslassen einer Taste eintragen
 * @param event Javascript Event
 */  
function handlekeyup(event){
    keyPressed[event.keyCode] = false;
}

/**
 * Fuehre bei jedem Tick entsprechend der gedrueckten Tasten Aktionen aus
 */ 
function handleKeys(){
    if(keyPressed[39]){
    	// Pfeil rechtes
    	if(controlCheck == 1){
    		rRobotY += 5;
    	}else if(controlCheck == 2){
    		rotateRobotY += 5;
    	}
    	else{
    		// TODO: hier noch anpassung für Roboterbewegung
    	}        
        keyPressed[39]=false;
    }
    if(keyPressed[37]){
    	// Pfeil links
    	if(controlCheck == 1){
    		rRobotY -= 5;
    	}else if(controlCheck == 2){
    		rotateRobotY -= 5;
    	}
    	else{
    		// TODO: hier noch anpassung für Roboterbewegung
    	}
        keyPressed[37]=false;
    }
    if(keyPressed[40]){
    	// Pfeil runter
    	if(controlCheck == 1){
    		rRobotX += 5;
    	}else if(controlCheck == 2){
    		rotateRobotX += 5;
    	}
    	else{
    		// TODO: hier noch anpassung für Roboterbewegung
    	}
        keyPressed[40]=false;
    }
    if(keyPressed[38]){
    	// Pfeil hoch
    	if(controlCheck == 1){
    		rRobotX -= 5;
    	}else if(controlCheck == 2){
    		rotateRobotX -= 5;
    	}
    	else{
    		// TODO: hier noch anpassung für Roboterbewegung
    	}
        keyPressed[38]=false;
    }
    if (keyPressed[33] || keyPressed[107]){
    	// Bild hoch
        zoom -= 5;
        keyPressed[33]=false;
    }
    if(keyPressed[34] || keyPressed[109]){
    	// Bild runter
        zoom += 5;
        keyPressed[34]=false;
    }
    if(keyPressed[65]){
        // A
        if(rotateSceneY <= 0){
            rotateSceneY = 359;
        } else {
            rotateSceneY -= 1;
        }        
    }
    if(keyPressed[68]){
        // D
        rotateSceneY = (rotateSceneY + 1) % 360;
    }
    if(keyPressed[83]){
        // W
        rotateSceneX = (rotateSceneX + 1) % 360;
    }
    if(keyPressed[87]){
        // S
        if(rotateSceneX <= 0){
            rotateSceneX = 359;
        } else {
            rotateSceneX -= 1;
        }
    }
    if(keyPressed[81]){
        // Q
        if(rotateSceneZ <= 0){
            rotateSceneZ = 359;
        } else {
            rotateSceneZ -= 1;
        }
    }
    if(keyPressed[69]){
        // E
        rotateSceneZ = (rotateSceneZ + 1) % 360;
    }
    if(keyPressed[89]){
		// Left translation, key "y"
		xTrans += 1;
	}
	if(keyPressed[88]){
		// Right translation, key "x"
		xTrans -= 1;
	}
	if(keyPressed[48] || keyPressed[96]){
		// Reset Position, key "0"
		rotateRobotX = 0;
		rotateRobotY = 0;
		rRobotX = 0;
		rRobotY = 0;
		rotateSceneX = 0;
		rotateSceneY = 0;
		rotateSceneZ = 0;
		xTrans = 0;
		yTrans = 0;
		zoom = startzoom;
		reset = true;
	}
	if(keyPressed[49]){
		// Right translation, key "1"
		rotateRobotX = 0;
		rotateRobotY = 0;
		controlCheck = 1;
	}
	if(keyPressed[50]){
		// Right translation, key "2"
		rotateRobotX = 0;
		rotateRobotY = 0;
		controlCheck = 2;
	}
	if(keyPressed[51]){
		// Right translation, key "3"
		rotateRobotX = 0;
		rotateRobotY = 0;
		controlCheck = 3;
	}
    
    
    
    document.getElementById("GUI_rotate").value = rotateRobotY;
    document.getElementById("GUI_swing").value = rotateRobotX;
    document.getElementById("GUI_zoom").value = zoom;
}

/**
 * Hauptroutine des Programms
 */                 
function main(){
    canvas = document.getElementById("webgl_canvas");
    initGL(canvas);
    initShaders();
    initBuffers();
    initTextures();
    
    document.onkeydown = handlekeydown;
    document.onkeyup = handlekeyup;
    
    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    gl.enable(gl.DEPTH_TEST);
    
    setCurvePoints();
    tick();    
}
